1   // Copyright 2014 The Apache Software Foundation
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   // http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  package org.apache.tapestry5.ioc.internal;
15  
16  import java.io.File;
17  import java.lang.reflect.Array;
18  import java.math.BigDecimal;
19  import java.math.BigInteger;
20  import java.util.Arrays;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.List;
24  
25  import org.apache.tapestry5.func.Flow;
26  import org.apache.tapestry5.ioc.Configuration;
27  import org.apache.tapestry5.ioc.services.Coercion;
28  import org.apache.tapestry5.ioc.services.CoercionTuple;
29  import org.apache.tapestry5.ioc.services.TypeCoercer;
30  import org.apache.tapestry5.ioc.util.TimeInterval;
31  
32  /**
33   * Class that provides Tapestry-IoC's basic type coercions.
34   * @see TypeCoercer
35   * @see Coercion
36   */
37  public class BasicTypeCoercions
38  {
39      /**
40       * Provides the basic type coercions to a {@link Configuration} instance. 
41       */
42      public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
43      {
44          add(configuration, Object.class, String.class, new Coercion<Object, String>()
45          {
46              @Override
47              public String coerce(Object input)
48              {
49                  return input.toString();
50              }
51          });
52  
53          add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
54          {
55              @Override
56              public Boolean coerce(Object input)
57              {
58                  return input != null;
59              }
60          });
61  
62          add(configuration, String.class, Double.class, new Coercion<String, Double>()
63          {
64              @Override
65              public Double coerce(String input)
66              {
67                  return Double.valueOf(input);
68              }
69          });
70  
71          // String to BigDecimal is important, as String->Double->BigDecimal would lose
72          // precision.
73  
74          add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
75          {
76              @Override
77              public BigDecimal coerce(String input)
78              {
79                  return new BigDecimal(input);
80              }
81          });
82  
83          add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
84          {
85              @Override
86              public Double coerce(BigDecimal input)
87              {
88                  return input.doubleValue();
89              }
90          });
91  
92          add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
93          {
94              @Override
95              public BigInteger coerce(String input)
96              {
97                  return new BigInteger(input);
98              }
99          });
100 
101         add(configuration, String.class, Long.class, new Coercion<String, Long>()
102         {
103             @Override
104             public Long coerce(String input)
105             {
106                 return Long.valueOf(input);
107             }
108         });
109 
110         add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
111         {
112             @Override
113             public Byte coerce(Long input)
114             {
115                 return input.byteValue();
116             }
117         });
118 
119         add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
120         {
121             @Override
122             public Short coerce(Long input)
123             {
124                 return input.shortValue();
125             }
126         });
127 
128         add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
129         {
130             @Override
131             public Integer coerce(Long input)
132             {
133                 return input.intValue();
134             }
135         });
136 
137         add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
138         {
139             @Override
140             public Long coerce(Number input)
141             {
142                 return input.longValue();
143             }
144         });
145 
146         add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
147         {
148             @Override
149             public Float coerce(Double input)
150             {
151                 return input.floatValue();
152             }
153         });
154 
155         add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
156         {
157             @Override
158             public Double coerce(Long input)
159             {
160                 return input.doubleValue();
161             }
162         });
163 
164         add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
165         {
166             @Override
167             public Boolean coerce(String input)
168             {
169                 String trimmed = input == null ? "" : input.trim();
170 
171                 if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
172                     return false;
173 
174                 // Any non-blank string but "false"
175 
176                 return true;
177             }
178         });
179 
180         add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
181         {
182             @Override
183             public Boolean coerce(Number input)
184             {
185                 return input.longValue() != 0;
186             }
187         });
188 
189         add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
190         {
191             @Override
192             public Boolean coerce(Void input)
193             {
194                 return false;
195             }
196         });
197 
198         add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
199         {
200             @Override
201             public Boolean coerce(Collection input)
202             {
203                 return !input.isEmpty();
204             }
205         });
206 
207         add(configuration, Object.class, List.class, new Coercion<Object, List>()
208         {
209             @Override
210             public List coerce(Object input)
211             {
212                 return Collections.singletonList(input);
213             }
214         });
215 
216         add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
217         {
218             @Override
219             public List coerce(Object[] input)
220             {
221                 return Arrays.asList(input);
222             }
223         });
224 
225         add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
226         {
227             @Override
228             public Boolean coerce(Object[] input)
229             {
230                 return input != null && input.length > 0;
231             }
232         });
233 
234         add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
235         {
236             @Override
237             public Double coerce(Float input)
238             {
239                 return input.doubleValue();
240             }
241         });
242 
243         Coercion primitiveArrayCoercion = new Coercion<Object, List>()
244         {
245             @Override
246             public List<Object> coerce(Object input)
247             {
248                 int length = Array.getLength(input);
249                 Object[] array = new Object[length];
250                 for (int i = 0; i < length; i++)
251                 {
252                     array[i] = Array.get(input, i);
253                 }
254                 return Arrays.asList(array);
255             }
256         };
257 
258         add(configuration, byte[].class, List.class, primitiveArrayCoercion);
259         add(configuration, short[].class, List.class, primitiveArrayCoercion);
260         add(configuration, int[].class, List.class, primitiveArrayCoercion);
261         add(configuration, long[].class, List.class, primitiveArrayCoercion);
262         add(configuration, float[].class, List.class, primitiveArrayCoercion);
263         add(configuration, double[].class, List.class, primitiveArrayCoercion);
264         add(configuration, char[].class, List.class, primitiveArrayCoercion);
265         add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
266 
267         add(configuration, String.class, File.class, new Coercion<String, File>()
268         {
269             @Override
270             public File coerce(String input)
271             {
272                 return new File(input);
273             }
274         });
275 
276         add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
277         {
278             @Override
279             public TimeInterval coerce(String input)
280             {
281                 return new TimeInterval(input);
282             }
283         });
284 
285         add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
286         {
287             @Override
288             public Long coerce(TimeInterval input)
289             {
290                 return input.milliseconds();
291             }
292         });
293 
294         add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
295         {
296             @Override
297             public Object[] coerce(Object input)
298             {
299                 return new Object[]
300                         {input};
301             }
302         });
303 
304         add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
305         {
306             @Override
307             public Object[] coerce(Collection input)
308             {
309                 return input.toArray();
310             }
311         });
312         
313         configuration.add(CoercionTuple.create(Flow.class, List.class, new Coercion<Flow, List>()
314         {
315             @Override
316             public List coerce(Flow input)
317             {
318                 return input.toList();
319             }
320         }));
321 
322         configuration.add(CoercionTuple.create(Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
323         {
324             @Override
325             public Boolean coerce(Flow input)
326             {
327                 return !input.isEmpty();
328             }
329         }));
330         
331 
332     }
333 
334     private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
335                                    Class<T> targetType, Coercion<S, T> coercion)
336     {
337         configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
338     }
339     
340     
341 
342 }